package jot.jot;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

/**
 * json转为实体类（不包括赋值）
 *
 * @author liujiamiao
 * @email 2544296058@qq.com
 * @date 2020-10-27 14:54
 */
public class JsonGenerate {
    //包名
    private static String packageName = null;
    //读取/写入的文件路径
    private static String path = null;
    //记录已生成的类名
    private static Set<String> clazzList = new HashSet<String>();

    public static void main(String[] args) throws IOException {
        //文件名
        String jsonName = "GenerateJson.json";
        //包名
        packageName = "com.chunuo.json";
        //路径
        path = "D:\\JAVA\\poi\\";
        //读取文件内容
        String xml = read(path, jsonName);
        //开始初始化和创建
        init(xml,jsonName);
    }


    public static void init(String xml, String jsonName) throws IOException {

        //获取java文件名
        int index = jsonName.indexOf(".");
        String clazzName = null;
        if(index==-1){
            clazzName = jsonName;
        }else{
            clazzName = jsonName.substring(0,index);
        }

        //构建java文本
        String java = build(xml,clazzName);
        System.out.println(java);

        //写入到java类中
        write(path+(packageName.replace('.','\\')),clazzName+".java",java.toString());
    }

    /**
     * 构建java类内容
     * @param xml
     * @return
     */
    private static String build(String xml, String clazzName) throws IOException {
        //封装对象属性的key和value
        Map<String, Object> map = new HashMap<>();
        //java类的内容，拼完串就写到文件里面
        StringBuilder java = new StringBuilder();

        int left = xml.indexOf("{");
        int right = xml.lastIndexOf("}");
        if(left!=-1&&right!=-1&&left<right){
            //初始代码
            java.append("package "+packageName+";\r\n\r\n" +
                    "import java.util.*;\r\n\r\n/**\n" +
                    " * 类的作用\n" +
                    " * @author liujiamiao\n" +
                    " * @email 2544296058@qq.com\n" +
                    " */\r\n" +
                    "public class "+clazzName+" {\r\n");
            //获取所有属性
            String sub = xml.substring(left + 1, right).trim();
            //拆分为多个属性
//            String[] fields = sub.split(",");
            //由于字段中有集合或map属性，则会拆分混乱，所以需要自己写一个split方法
            List<String> fields = split(sub);

            for(String field : fields){
                int leftObj = -1;
                if(field.indexOf('[')!=-1&&field.indexOf(']')!=-1){
                    //属性拆分为key：value
                    int index = field.indexOf(':');
                    //属性名
                    String key = subString(field.substring(0,index).trim(),true);
                    //属性类型
                    String fieldType = "Object";
                    //集合的值 [xx,xx,xx]
                    String temp = field.substring(index+1).trim();
                    if(temp.indexOf('{')!=-1&&temp.indexOf('}')!=-1){
                        //判断命名规范
                        int tempIndex = -1;
                        tempIndex = key.charAt(key.length()-1)=='s'?key.length()-1:-1;
                        if(tempIndex==-1){
                            tempIndex = key.indexOf("List");
                            if(tempIndex == -1){
                                throw new RuntimeException("属性名不规范，无法判断其类名，默认为Object，集合命名格式为：xxxList | xxxs");
                            }
                        }
                        //获取该类的名字
                        fieldType = key.substring(0,1).toUpperCase()+key.substring(1,tempIndex);
                        //再次创建一个java实体类,如果该类已经创建过，则不需要再次创建
                        if(!clazzList.contains(fieldType)){
                            //集合中的对象json
                            List<String> fieldClazzObjList = split(temp.substring(1,temp.length()-1));
                            //存储key（重点）-value，需要确保所有的字段
                            Map<String, Object> tempObj = new HashMap<>();
                            //{},{},{}
                            for(String fieldClazzObj:fieldClazzObjList){

                                if(fieldClazzObj.indexOf(']')==-1){
                                    //去掉两边的{  }
                                    fieldClazzObj = fieldClazzObj.substring(1,fieldClazzObj.length()-1);
                                    //key-value
                                    String[] split = fieldClazzObj.split(",");
                                    for(String sp : split){
                                        String[] obj = sp.split(":");
                                        tempObj.put(obj[0].trim(),obj[1].trim());
                                    }
                                }else{
                                    throw new RuntimeException("集合中的对象又包含集合，出现异常！");
                                }

                            }
                            //将遍历集合属性中所有对象属性后都存储到map的集合
                            StringBuilder sb = new StringBuilder("{");
                            Set<Map.Entry<String, Object>> entrySet = tempObj.entrySet();
                            int count = 0;
                            for(Map.Entry entry:entrySet){
                                count ++;
                                if(count>1)
                                    sb.append(",");
                                sb.append(entry.getKey()+":"+entry.getValue());
                            }
                            sb.append("}");
                            clazzList.add(fieldType);
                            init(sb.toString(),fieldType);
                        }
                    }else if(object(temp)){
                        //含有多种类型，泛型为Object
                    }else if(temp.indexOf('"')!=-1||temp.indexOf("\'")!=-1){
                        fieldType = "String";
                    }else if(temp.indexOf('.')!=-1) {
                        fieldType = "Float";
                    }else{
                        fieldType = "Integer";
                    }
                    //属性名和属性值
                    map.put(key,"List<"+fieldType+">()");
                } else if(field.indexOf('{')!=-1&&field.lastIndexOf('}')!=-1){//对象属性，需要再生成一个对象
                    //属性拆分为key：value
                    int index = field.indexOf(':');
                    //属性名和属性值
                    String key = subString(field.substring(0,index).trim(),true);
                    //属性名和属性值
                    String fieldClazzName = key.substring(0,1).toUpperCase()+key.substring(1);
                    map.put(key,"Object<"+fieldClazzName+">()");

                    //再次创建一个java实体类,如果该类已经创建过，则不需要再次创建
                    if(!clazzList.contains(fieldClazzName)){
                        clazzList.add(fieldClazzName);
                        int i = field.indexOf('{');
                        int j = field.lastIndexOf('}');
                        init(field.substring(i,j+1),fieldClazzName);
                    }

                } else{
                    //不是对象属性，不可能有多个":"健值队，也就是说 =》 引用类型
                    String[] obj = field.split(":");
                    if(obj.length>2){
                        throw new RuntimeException("json格式错误！请检查是否忽略\",\" ："+field);
                    }
                    //属性名和属性值
                    map.put(subString(obj[0].trim(),true),subString(obj[1].trim(),false));
                }
            }

            //遍历所有属性
            Set<Map.Entry<String, Object>> entrySet = map.entrySet();
            for(Map.Entry entry:entrySet){
                String type = getType(entry.getValue());
                java.append("\tprivate "+type+" "+entry.getKey()+";\r\n");
            }
            //构造方法
            java.append("\tpublic "+clazzName+"() {\r\n");

            //构造方法的初始化代码
//            for(String sb : list){
//                java.append(sb);
//            }
            //结束
            java.append("\t}\r\n}");
            return java.toString();
        }else{
            throw new RuntimeException("json格式不正确！");
        }
    }

    /**
     * 判断集合是否含有多种数据类型
     * @param temp
     * @return
     */
    private static boolean object(String temp) {
        if(temp.indexOf("{")!=-1)
            return false;//不封装对象类型
        String val = temp.substring(1,temp.length()-1);
        String[] fields = val.split(",");
        int a = 0,b = 0,c = 0;
        for(String field : fields){
            if(field.trim().indexOf('"')!=-1){
                a++;//字符串
            }else if(field.trim().indexOf('.')!=-1){
                b++;//精度形
            }else{
                c++;//整形
            }
        }
        //只有一种数据类型
        if((a>b?(a>c?a:c):(b>c?b:c))==fields.length){
            return false;
        }
        //含有多种数据类型
        return true;
    }

    /**
     * 对象根据","拆分属性
     * 如 {
     * PersonList:[{},{}],
     * Person:{},
     * }
     * 拆分为：PersonList:[{},{}]  和  Person:{}
     * @param sub
     * @return
     */
    private static List<String> split(String sub) {
        List<String> list = new ArrayList<String>();
        int a = 0;//表示数组
        int o = 0;//表示map对象属性
        int index = -1;
        for(int i = 0;i<sub.length();i++){
            if(sub.charAt(i)=='['){
                a++;
            }else if(sub.charAt(i)==']'){
                a--;
            }else if(sub.charAt(i)=='{'){
                o++;
            }else if(sub.charAt(i)=='}'){
                o--;
            }else if(sub.charAt(i)==','&&a==0&&o==0){
                list.add(sub.substring(index+1,i));
                index = i;
            }
        }
        if(sub.charAt(sub.length()-1)!=','){
            list.add(sub.substring(index+1));
        }
        return  list;
    }

    /**
     * 根据value获取属性类型
     * @param value
     * @return
     */
    private static String getType(Object value) {
        int len = 0;
        if(value.toString().indexOf('"')!=-1||value.toString().indexOf("\'")!=-1){
            return "String";
        }else if((len = value.toString().indexOf('.'))!=-1){
            //精度小于6的是float类型，否则是double类型
            if(value.toString().length()-len<=6){
                try {
                    Float.parseFloat(value.toString());
                    return "Float";
                } catch (NumberFormatException e) {
                    throw new RuntimeException("类型错误，既不是字符串，又不是精度类型 ："+value.toString());
                }
            }else{
                try {
                    Double.parseDouble(value.toString());
                    return "Double";
                } catch (NumberFormatException e) {
                    throw new RuntimeException("类型错误，既不是字符串，又不是精度类型 ："+value.toString());
                }
            }
        }else if(value.toString().equals("true")||value.toString().equals("false")){
            return "Boolean";
        }else if(value.toString().indexOf("List")!=-1){
            //判断list属性类型
            int i = value.toString().indexOf('<');
            int j = value.toString().indexOf('>');
            return "List<"+value.toString().substring(i+1,j)+">";
        }else if(value.toString().indexOf("Object")!=-1){
            //判断map属性类型
            //准备更改为对象类型，而不是map
            int i = value.toString().indexOf('<');
            int j = value.toString().indexOf('>');
            return value.toString().substring(i+1,j);
        }else {
            return "Integer";
        }
    }

    /**
     * 截取key/value的值，去掉""
     * @param field
     * @return
     */
    public static String subString(String field, boolean isKey){
        if(field.indexOf('"')!=-1||field.indexOf("\'")!=-1){
            //说明字段用了""围起来
            int i = field.indexOf('"');
            int j = field.lastIndexOf('"');
            if(i==-1&&j==-1){
                i = field.indexOf("\'");
                j = field.lastIndexOf("\'");
            }
            if(i!=-1&&j!=-1&&i<j){
                if(isKey){
                    //说明是key，需要去掉"";
                    return field.substring(i+1,j);
                }else{
                    //说明是value，是字符串
                    return field;
                }

            }else{
                throw new RuntimeException("json格式不正确！field只有一个\" ："+field);
            }
        }else{
            //没有用""围起来，可能是key或者不是字符串
            if(field.indexOf(" ")!=-1){
                throw new RuntimeException("json语法不正确！field含有空格："+field);
            }
            return field;
        }
    }

    /**
     * 读取文件内容
     * @param path
     * @param fileName
     * @return
     * @throws IOException
     */
    public static String read(String path , String fileName) throws IOException {
        //读取
        FileReader reader = new FileReader(new File(path,fileName));
        char[] buf = new char[50];
        int len = -1;
        StringBuilder sb = new StringBuilder();
        while((len = reader.read(buf))!=-1){
            sb.append(new String(buf,0,len));
        }
        reader.close();
        return sb.toString();
    }

    /**
     * 写入文件
     * @param path
     * @param fileName
     * @param content
     * @throws IOException
     */
    public static void write(String path, String fileName, String content) throws IOException {
        System.out.println(path);
        File filePath = new File(path);
        if(!filePath.exists()){
            filePath.mkdirs();
        }
        File file = new File(path, fileName);
        FileWriter writer = new FileWriter(file);
        writer.write(content);
        writer.flush();
        writer.close();
    }

    public static void show(List list){
        for(int i = 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
}
